import logging
import time
import os
import re
from logging.handlers import RotatingFileHandler
from logging import StreamHandler
from config.constant import LOGS_DIR

# 核心配置（简化合并重复项，依赖constant.py中已读取的ENV，无需单独处理.env）
SERVICE_NAME = "order-service"
LEVEL_CONFIG = {
    "DEBUG": {"dir": "debug", "level": logging.DEBUG, "retention": 3, "size": 50 * 1024 * 1024, "backup": 5,
              "prod": False},
    "INFO": {"dir": "info", "level": logging.INFO, "retention": 15, "size": 100 * 1024 * 1024, "backup": 10,
             "prod": True},
    "WARNING": {"dir": "warning", "level": logging.WARNING, "retention": 30, "size": 100 * 1024 * 1024, "backup": 10,
                "prod": True},
    "ERROR": {"dir": "error", "level": logging.ERROR, "retention": 90, "size": 100 * 1024 * 1024, "backup": 20,
              "prod": True}
}


# 敏感信息脱敏（简化正则）
def desensitize(msg):
    msg = str(msg)
    # 手机号脱敏：保留前3位和后4位，中间用****替换
    msg = re.sub(r"1[3-9]\d{9}", lambda m: f"{m.group(0)[:3]}****{m.group(0)[7:]}", msg)
    # 银行卡号脱敏：保留前4位和后4位，中间用****替换（支持16-19位卡号）
    msg = re.sub(r"\d{16,19}", lambda m: f"{m.group(0)[:4]}****{m.group(0)[-4:]}", msg)
    return msg


# 日志上下文过滤器（简化参数，注入核心上下文信息）
class ContextFilter(logging.Filter):
    def __init__(self, request_id="N/A", user_id="N/A"):
        self.request_id = request_id  # 请求唯一标识（追踪链路用）
        self.user_id = user_id  # 用户标识（定位操作人用）

    def filter(self, record):
        # 向日志记录中添加自定义字段
        record.service = SERVICE_NAME  # 服务名称（便于多服务日志区分）
        record.env = os.getenv("APP_ENV", "dev")  # 环境标识（依赖constant.py加载的.env配置）
        record.request_id = self.request_id
        record.user_id = self.user_id
        # 日志内容脱敏（敏感信息处理）
        record.msg = desensitize(record.msg)
        return True


# 过期日志清理（按级别配置的保留天数删除旧日志）
def clean_expired_logs():
    current_env = os.getenv("APP_ENV", "dev")
    for level, cfg in LEVEL_CONFIG.items():
        # 生产环境跳过非生产级别的日志清理（如DEBUG日志）
        if current_env == "prod" and not cfg["prod"]:
            continue
        # 拼接日志目录路径（依赖constant.py定义的LOGS_DIR）
        log_dir = os.path.join(LOGS_DIR, SERVICE_NAME, current_env, cfg["dir"])
        if not os.path.exists(log_dir):
            continue  # 目录不存在则跳过
        # 计算过期时间戳（当前时间 - 保留天数*一天秒数）
        expire_ts = time.time() - cfg["retention"] * 86400
        # 遍历目录下文件，删除过期日志
        for file_name in os.listdir(log_dir):
            file_path = os.path.join(log_dir, file_name)
            # 仅删除文件类型且创建时间早于过期时间的日志
            if os.path.isfile(file_path) and os.path.getctime(file_path) < expire_ts:
                os.remove(file_path)


# 日志实例生成（核心方法，单例模式避免重复创建处理器）
def get_logger(module_name="default", request_id=None, user_id=None):
    # 日志器名称：服务名.模块名（便于定位日志来源）
    logger_name = f"{SERVICE_NAME}.{module_name}"
    logger = logging.getLogger(logger_name)

    # 单例模式：若已存在处理器，直接返回实例（避免重复添加handler）
    if logger.handlers:
        return logger

    current_env = os.getenv("APP_ENV", "dev")
    # 基础配置：开发环境默认DEBUG级别，生产环境默认INFO级别
    logger.setLevel(logging.DEBUG if current_env == "dev" else logging.INFO)
    logger.propagate = False  # 禁止日志向上传递（避免root logger重复输出）

    # 添加上下文过滤器（注入服务、环境、请求ID等信息）
    context_filter = ContextFilter(request_id, user_id)
    logger.addFilter(context_filter)

    # 1. 控制台输出（仅开发环境启用，便于本地调试）
    if current_env == "dev":
        console_handler = StreamHandler()
        console_handler.setLevel(logging.WARNING)  # 控制台仅输出WARNING及以上级别
        # 控制台日志格式：时间 + 级别 + 服务名 + 请求ID + 日志内容（简化格式，便于快速查看）
        console_formatter = logging.Formatter(
            "[%(asctime)s] [%(levelname)s] [%(service)s] [req_id=%(request_id)s] %(message)s"
        )
        console_handler.setFormatter(console_formatter)
        logger.addHandler(console_handler)

    # 2. 文件处理器（按级别分目录存储，支持按文件大小轮转）
    for level, cfg in LEVEL_CONFIG.items():
        # 生产环境跳过非生产级别的日志文件（如DEBUG日志）
        if current_env == "prod" and not cfg["prod"]:
            continue
        # 拼接日志文件目录（LOGS_DIR/服务名/环境名/级别目录/模块名）
        log_dir = os.path.join(LOGS_DIR, SERVICE_NAME, current_env, cfg["dir"], module_name)
        # 确保目录存在（不存在则创建，避免文件写入失败）
        os.makedirs(log_dir, exist_ok=True)
        # 日志文件名：级别_模块名.log（如info_order.log）
        log_file_path = os.path.join(log_dir, f"{level.lower()}_{module_name}.log")

        # 配置文件轮转：按大小切割，保留指定数量的备份文件
        file_handler = RotatingFileHandler(
            log_file_path,
            maxBytes=cfg["size"],  # 单个文件最大大小（如100MB）
            backupCount=cfg["backup"],  # 备份文件数量（如10个）
            encoding="utf-8"  # 编码格式（避免中文乱码）
        )
        # 文件处理器仅处理对应级别的日志（如INFO处理器只处理INFO及以上）
        file_handler.setLevel(cfg["level"])
        # 文件日志格式：包含完整上下文信息（便于日志分析和问题定位）
        file_formatter = logging.Formatter(
            "[%(asctime)s] [%(levelname)s] [%(service)s] [%(env)s] [%(module)s] "
            "[pid=%(process)d] [req_id=%(request_id)s] [user=%(user_id)s] %(message)s"
        )
        file_handler.setFormatter(file_formatter)
        logger.addHandler(file_handler)

    # 触发过期日志清理（每次创建日志实例时执行，确保日志不堆积）
    clean_expired_logs()
    return logger


# 兼容旧调用方式（若原有代码用get_log获取日志，保持兼容）
get_log = get_logger